﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;
using CloudShot.Entities;

namespace CloudShot.Utils
{
  internal static class AppHelper
  {
    #region Sompe Public Consts
    //TODO: I do not like this, but for now it should be here

    public const string ProjectWebsiteUrl = @"http://cloudshot.codeplex.com";
    public const string WhatIsNewUrl = @"http://cloudshot.codeplex.com/#whatisnew";
    public const string HelpUrl = @"http://cloudshot.codeplex.com/documentation";
    public const string FeedbackEmail = @"chill.hr@gmail.com";

    public static readonly List<KeyValuePair<string, Uri>> Developers = new List<KeyValuePair<string, Uri>>
    {
      new KeyValuePair<string, Uri>("Archil Tskhondiya", new Uri("https://www.linkedin.com/in/atskhondiya")),
      new KeyValuePair<string, Uri>("Dmitry Astapkovich", new Uri("https://www.linkedin.com/in/dastapkovich")),
      new KeyValuePair<string, Uri>("Simon Korzunov", new Uri("https://www.linkedin.com/in/skorzunov")),
    };

    #endregion

    /// <summary>
    /// Application update interval.
    /// </summary>
    public static TimeSpan UpdateInterval = TimeSpan.FromHours(8);

    /// <summary>
    /// Short application update interval.
    /// </summary>
    public static TimeSpan ShortUpdateInterval = TimeSpan.FromMinutes(5);

    private static string _cloudShotAppData;

    private static string _defaultConfig;

    private static string _configFile;

    private static string _recentShotsFile;

    private static string _errorFile;

    private static string _thumbnailsPath;

    private static string _pluginsPath;

    public static string CloudShotAppData
    {
      get
      {
        if (string.IsNullOrEmpty(_cloudShotAppData))
          _cloudShotAppData = Application.UserAppDataPath.Replace(Application.ProductVersion, "");

        return _cloudShotAppData;
      }
    }

    public static string DefaultConfig
    {
      get
      {
        if (string.IsNullOrEmpty(_defaultConfig))
          _defaultConfig = Path.Combine(Application.StartupPath, @"default.json");

        return _defaultConfig;
      }
    }

    public static string ConfigFile
    {
      get
      {
        if (string.IsNullOrEmpty(_configFile))
          _configFile = Path.Combine(CloudShotAppData, Application.ProductName + @".json");

        return _configFile;
      }
    }

    public static string RecentShotsFile
    {
      get
      {
        if (string.IsNullOrEmpty(_recentShotsFile))
          _recentShotsFile = Path.Combine(CloudShotAppData, @"RecentShots.json");

        return _recentShotsFile;
      }
    }

    public static string ErrorFile
    {
      get
      {
        if (string.IsNullOrEmpty(_errorFile))
          _errorFile = Path.Combine(CloudShotAppData, @"Errors.log");

        return _errorFile;
      }
    }

    public static string ThumbnailsPath
    {
      get
      {
        if (string.IsNullOrEmpty(_thumbnailsPath))
          _thumbnailsPath = Path.Combine(CloudShotAppData, @"Thumbnails");

        return _thumbnailsPath;
      }
    }

    public static string PluginsPath
    {
      get
      {
        if (string.IsNullOrEmpty(_pluginsPath))
          _pluginsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"CloudShot\Plugins");

        return _pluginsPath;
      }
    }

    public static IEnumerable<Type> FindDerivedTypesFromAssembly(this Assembly assembly, Type baseType)
    {
      if (assembly == null)
        throw new ArgumentNullException("assembly", "Assembly must be defined");

      if (baseType == null)
        throw new ArgumentNullException("baseType", "Parent Type must be defined");

      Type[] types = assembly.GetExportedTypes();

      // works out the derived types
      foreach (var type in types)
      {
        // it must be a class
        if (!type.IsClass || type.IsAbstract)
          continue;

        if (baseType.IsInterface)
        {
          var it = type.GetInterface(baseType.FullName);

          if (it != null)
            // add it to result list
            yield return type;
        }
        else if (type.IsSubclassOf(baseType))
        {
          // add it to result list
          yield return type;
        }
      }
    }

    public static string GenerateShotName(ImageFormat imageFormat, ShotType shotType)
    {
      string prefix = shotType == ShotType.Record ? "record" : "shot";
      return string.Format("{0}_{1:yyMMdd_HHmmss}{2}", prefix, DateTime.Now, imageFormat.GetExtension()).ToLower();
    }

    // <summary>
    // Get the name of a static or instance property from a property access lambda.
    // </summary>
    // <typeparam name="T">Type of the property</typeparam>
    // <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
    // <returns>The name of the property</returns>
    public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
    {
      var me = propertyLambda.Body as MemberExpression;

      if (me == null)
      {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
      }

      return me.Member.Name;
    }

    public static void OpenInViewer(string path)
    {
      try
      {
        Process.Start(path);
      }
      catch (Exception err)
      {
        ErrorsHelper.ShowError(err);
      }
    }
  }
}